use std::mem;

/// 数组（array）是一组拥有相同类型 T 的对象的集合，在内存中是连续存储的。数组使用中括号 [] 来创建，且它们的大小在编译时会被确定。数组的类型标记为 [T; length]
/// （译注：T 为元素类型，length 表示数组大小）。
///
/// 切片（slice）类型和数组类似，但其大小在编译时是不确定的。相反，切片是一个双字对象（two-word object），
/// 第一个字是一个指向数据的指针，第二个字是切片的长度。这个 “字” 的宽度和 usize 相同，由处理器架构决定，比如在 x86-64 平台上就是 64 位。
/// slice 可以用来借用数组的一部分。slice 的类型标记为 &[T]。

fn main() {
    // 数组
    // array_test()

    // 切片
    slice_test();

    // array
    // array();
}

#[allow(dead_code)]
fn slice_test() {
    let mut str = String::from("hello world");
    let str1 = &str[0..5];
    let str3 = &str[..3];
    let str2 = &str[6..];
    println!("str1 = {}, str2 = {}, str3 = {}", str1, str2, str3);
    let word = first_word(&str);
    println!("{}", word);
    str.clear();
}

fn first_word(str: &String) -> usize {
    // todo!()
    // 逐个元素的检查 String 中的值是否为空格，需要用 as_bytes 方法将 String 转化为字节数组
    let bytes = str.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    str.len()
}

#[allow(dead_code)]
fn array() {
    // 类型和长度
    let a = [1, 2, 3, 4, 5];
    for i in a.iter() {
        println!("{}", i);
    }

    // 如果数组中每个元素都相等可以下面这样声明
    let b = [5; 5];
    for i in b.iter() {
        println!("{}", i);
    }
}

#[allow(dead_code)]
fn array_test() {
    let xs = [1, 2, 3, 4, 5];
    println!("a[0] = {}", xs[0]);

    // 修改数组中的值
    let mut b: [i64; 5] = [1, 2, 3, 4, 5];
    b[0] = 100;
    println!("b[0] = {}", b[0]);

    // 所有元素可以初始化成相同的值
    let ys: [i32; 3] = [0; 3];
    for i in &ys {
        println!("{}", i);
    }
    // `len` 返回数组的大小
    println!("array size: {}", ys.len());

    // 数组是在栈中分配的
    println!("array occupies {} bytes", mem::size_of_val(&xs));

    // 数组可以自动被借用成为 slice
    println!("borrow the whole array as a slice");
    // analyze_slice(&xs);

    // slice 可以指向数组的一部分
    println!("borrow a section of the array as a slice");
    // println!(xs[1..4]);

    // 越界的下标会引发致命错误（panic）
    println!("{}", xs[3]);
}
